//+------------------------------------------------------------------+
//|                                                      MA_BOLL_MACD.mq5 |
//|                        Copyright 2023, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade\Trade.mqh>

// 输入参数
input int MAPeriod = 14;          // 移动平均线周期
input int BandsPeriod = 5;       // 布林带周期
input double BandsDeviation = 2;  // 布林带标准差
input int FastMACD = 12;          // MACD 快线周期
input int SlowMACD = 26;          // MACD 慢线周期
input int SignalMACD = 9;         // MACD 信号线周期
input double LotSize = 0.01;       // 交易手数
input int StopLoss = 100;         // 止损点数
input int TakeProfit = 200;       // 止盈点数
input int MagicNumber = 123456;      // 订单魔术号
input int TrailingStopPoints = 50;   // 移动止损点数

CTrade trade;  // 交易对象

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// 初始化代码
   Print("Expert Advisor initialized.");
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// 反初始化代码
   Print("Expert Advisor deinitialized.");
  }


//+------------------------------------------------------------------+
//| 下单函数                                                         |
//+------------------------------------------------------------------+
bool PlaceOrder(int orderType,double current_price)
  {
// 计算止损和止盈价格
   double stopLoss = 0, takeProfit = 0;
   double price = (orderType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(StopLoss > 0)
     {
      stopLoss = (orderType == ORDER_TYPE_BUY) ? current_price - StopLoss * _Point : current_price + StopLoss * _Point;
     }
   if(TakeProfit > 0)
     {
      takeProfit = (orderType == ORDER_TYPE_BUY) ? current_price + TakeProfit * _Point : current_price - TakeProfit * _Point;
     }

// 定义交易请求结构体
   MqlTradeRequest request;
   ZeroMemory(request);
   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = LotSize;
   request.type = orderType;
   request.price = price;
   request.sl = stopLoss;
   request.tp = takeProfit;
   request.deviation = 10;
   request.magic = MagicNumber;
   request.comment = (orderType == ORDER_TYPE_BUY) ? "Buy Order" : "Sell Order";

// 定义交易结果结构体
   MqlTradeResult result;
   ZeroMemory(result);

// 发送交易请求
   if(!OrderSend(request, result))
     {
      Print("OrderSend failed. Error code: ", GetLastError());
      return false;
     }
   else
     {
      Print("Order placed successfully. Ticket: ", result.order);
      return true;
     }
  }



//+------------------------------------------------------------------+
//| 移动止损函数                                                     |
//+------------------------------------------------------------------+
void TrailingStop()
  {
   for (int i = PositionsTotal() - 1; i >= 0; i--) // 遍历所有持仓
     {
      ulong ticket = PositionGetTicket(i); // 获取持仓的订单号
      if (ticket > 0)
        {
         double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); // 当前持仓价格
         double open_price = PositionGetDouble(POSITION_PRICE_OPEN); // 开仓价格
         double sl = PositionGetDouble(POSITION_SL); // 当前止损价
         double tp = PositionGetDouble(POSITION_TP); // 当前止盈价
         ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // 持仓类型

         if (position_type == POSITION_TYPE_BUY) // 多单
           {
            double new_sl = current_price - TrailingStopPoints * _Point; // 计算新的止损价
            if (new_sl > sl) // 如果新的止损价高于当前止损价
              {
               trade.PositionModify(ticket, new_sl, tp); // 更新止损价
               Print("Buy position modified. New SL: ", new_sl);
              }
           }
         else if (position_type == POSITION_TYPE_SELL) // 空单
           {
            double new_sl = current_price + TrailingStopPoints * _Point; // 计算新的止损价
            if (new_sl < sl || sl == 0) // 如果新的止损价低于当前止损价或止损价为 0
              {
               trade.PositionModify(ticket, new_sl, tp); // 更新止损价
               Print("Sell position modified. New SL: ", new_sl);
              }
           }
        }
     }
  }
  
  
 //+------------------------------------------------------------------+
//| 平仓逻辑函数                                                     |
//+------------------------------------------------------------------+
void ClosePositionsOnReversal(bool is_uptrend, bool is_downtrend)
  {
   for (int i = PositionsTotal() - 1; i >= 0; i--) // 遍历所有持仓
     {
      ulong ticket = PositionGetTicket(i); // 获取持仓的订单号
      if (ticket > 0)
        {
         ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // 持仓类型

         if (position_type == POSITION_TYPE_BUY && is_downtrend) // 多单且趋势反转
           {
            if (trade.PositionClose(ticket)) // 平仓
              {
               Print("Buy position closed due to trend reversal.");
               Print("Trade result: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
              }
            else
              {
               Print("Failed to close Buy position. Error: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
              }
           }
         else if (position_type == POSITION_TYPE_SELL && is_uptrend) // 空单且趋势反转
           {
            if (trade.PositionClose(ticket)) // 平仓
              {
               Print("Sell position closed due to trend reversal.");
               Print("Trade result: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
              }
            else
              {
               Print("Failed to close Sell position. Error: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
              }
           }
        }
     }
  }


//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// 获取当前价格
   double current_price = iClose(Symbol(), PERIOD_CURRENT, 0);

// 计算移动平均线 (MA)
   double ma_value = iMA(Symbol(), PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);

// 计算布林带 (BOLL)
   double boll_upper = iBands(NULL, PERIOD_CURRENT, BandsPeriod, BandsDeviation, 0, 1);
   double boll_lower = iBands(Symbol(), PERIOD_CURRENT, BandsPeriod, BandsDeviation, 0,2);

// 计算 MACD
   double macd_main = iMACD(Symbol(), PERIOD_CURRENT, FastMACD, SlowMACD, SignalMACD, 0);
   double macd_signal = iMACD(Symbol(), PERIOD_CURRENT, FastMACD, SlowMACD, SignalMACD, 1);

// 判断趋势
   bool is_uptrend = (current_price > ma_value) && (macd_main > macd_signal);  // 上升趋势
   bool is_downtrend = (current_price < ma_value) && (macd_main < macd_signal); // 下降趋势

// 判断布林带突破
   bool is_boll_breakout_up = (current_price > boll_upper);   // 突破上轨
   bool is_boll_breakout_down = (current_price < boll_lower); // 突破下轨


   Print("is_downtrend卖出信号Sell order opened at pric: =====",is_downtrend,is_boll_breakout_down);
// 交易逻辑
   if (is_uptrend && is_boll_breakout_up)
     {
      // 买入信号
      if (PositionsTotal() == 0) // 如果没有持仓
        {
         double sl = current_price - StopLoss * _Point;  // 计算止损价
         double tp = current_price + TakeProfit * _Point; // 计算止盈价
         trade.Buy(LotSize, Symbol(), current_price, sl, tp); // 开多单
         Print("Buy order opened at price: ", current_price, " SL: ", sl, " TP: ", tp);
        }
     }
   else if (is_downtrend && is_boll_breakout_down)
     {
      // 卖出信号
      if (PositionsTotal() == 0) // 如果没有持仓
        {
         double sl = current_price + StopLoss * _Point;  // 计算止损价
         double tp = current_price - TakeProfit * _Point; // 计算止盈价
         trade.Sell(LotSize, Symbol(), current_price, sl, tp); // 开空单
         Print("Sell order opened at price: ", current_price, " SL: ", sl, " TP: ", tp);
        }
     }
      TrailingStop(); 
       // 平仓逻辑
      ClosePositionsOnReversal(is_uptrend, is_downtrend); // 调用平仓函数
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
